package de.hdu.mfz.dao;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import de.hdu.mfz.model.Mitfahrt;
import de.hdu.mfz.model.Route;
import de.hdu.mfz.model.Routenpunkt;
import de.hdu.mfz.model.User;

import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;


/**
 * Die Zugriffsklasse für Objekte vom Typ Route. Alle Aktivitäten mit der DB
 * bezüglich der Enität Route werden über diese Klasse gemacht!
 * @author Katharina, Steffi
 */
public class RouteDAO  extends HibernateDaoSupport  {
	private MitfahrtDAO mitfahrtDao;

	public void setMitfahrtDao(MitfahrtDAO mitfahrtDao) {
		this.mitfahrtDao = mitfahrtDao;
	}
	
	/**
	 * Speichert eine {@link Route} in die DB.
	 * @param route
	 */
	public void insert( Route route) {
		HibernateTemplate template = getHibernateTemplate(); 
		template.saveOrUpdate(route);	
	}
	
	/**
	 * Löscht das spezielle {@link Route} Objekt von der DB.
	 * @param route {@link Route} das gelöscht wird.
	 * @throws DaoException, wenn das {@link Route} Objekt in einer  {@link Mitfahrt} verwendet wird
	 */
	public void delete( Route route) throws DaoException {
		HibernateTemplate template = getHibernateTemplate();
		List <Mitfahrt> mitfahrtenVonRoute = mitfahrtDao.findByRoute(route); 
		if(mitfahrtenVonRoute.size() == 0) {
			template.delete(route);
		} else {
			throw new DaoException("Die Route kann nicht gelöscht werden, da bereits Fahrten zu dieser Route durchgeführt worden sind."); 
		}	
	}
	
	/**
	 * Liefert eine Route anhand des PK der DB
	 * @param ID des Primäry Keys{@link Route}
	 * @return eine einzelne Route
	 */
	public Route findById( int routeId) {
		HibernateTemplate template = getHibernateTemplate();
		return (Route) template.get(Route.class, routeId);
		
	}
	
	/**
	 * Liefert alle Routen der DB.
	 * @return Liste mit Routen
	 * @see Route
	 */
	@SuppressWarnings("unchecked")
	public List<Route> findAll() {
		HibernateTemplate template = getHibernateTemplate();
		@SuppressWarnings("rawtypes")
		List alleRouten = template.loadAll(Route.class);
		return (List<Route>) alleRouten;
	}
	
	/**
	 * Liefert eine Liste mit Routen zum einem Fahrer
	 * @param User {@link User} Objekt 
	 * @return Liste mit Routen 
	 */
	@SuppressWarnings("unchecked")
	public List<Route> findByFahrer(User fahrer) {
		HibernateTemplate template = getHibernateTemplate();
		List<Route> routenFahrer = template.find("from Route r where r.fahrer = ?", fahrer);
		return routenFahrer;
	}


	/**
	 * Suchen einer Route anhand bestimmten Kriterien
	 * @param startort
 	 * @param zielort
	 * @param abfahrtsdatum
	 * @return Liste mit Routen 
	 */
	public List<Route> findRoute(String startort, String zielort, Date abfahrtsdatum) {
		
		HibernateTemplate template = getHibernateTemplate();
		List<Route> alle = template.loadAll(Route.class);
		List<Route> result = new ArrayList<Route>(); 
		
		startort = startort.toUpperCase();
		zielort = zielort.toUpperCase();
		
		//Zeitwerte von Parameter abfahrtsdatum auf 0 setzen
		abfahrtsdatum = hilfsfunktion(abfahrtsdatum);
		
		//Alle Routen durchlaufen
		for(Route eineRoute: alle){
			Date d = hilfsfunktion(eineRoute.getStartzeit());
			
			//Wenn abfahrsdatum nicht übereinstimmt(!= 0) dann gleich zur nächsten Routen
			if(d.compareTo(abfahrtsdatum) != 0 )
				continue;
			
			boolean startfound = false;
			
			//Alle Routenpunkte pro Route durchlaufen
			for(Routenpunkt rp: eineRoute.getListe()){
				if(rp.getOrt().toUpperCase().equals(startort)){
					startfound=true;
				}

						
				if((rp.getOrt().toUpperCase().equals(zielort)) && 
				   (startfound == true)){
					result.add(eineRoute);
					
					//wird benötigt, wenn Zielort mehrmals vorkommt
					break;
				}	
			}
		}
		return result;	
	}
	
	
	/**
	 * Hilfsfunktion
	 * Setzt die Variablen Stunde, Minute, Sekunde und Millisekunde 
	 * eines Objekts vom Typ Calendar auf 0 
	 * @param Datum
	 * @return Datum  
	 */
	private Date hilfsfunktion(Date d){
		
		Calendar cal = Calendar.getInstance();
		cal.setTime(d);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
	}
	
}